/*
 * Copyright (c) 2009-2010 HIT Microelectronic Center
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *
 * Authors: Gou Pengfei
 *
 * Date: Dec. 2009
 *
 */

#include <queue>

#include "base/timebuf.hh"
#include "config/the_isa.hh"
#include "cpu/edge/fu_pool.hh"
#include "cpu/edge/execute.hh"
#include "params/DerivEdgeCPU.hh"

using namespace std;

template<class Impl>
SimpleEdgeExecute<Impl>::SimpleEdgeExecute(CPU *_cpu, DerivEdgeCPUParams *params)
    : issueToExecQueue(params->backComSize, params->forwardComSize),
      cpu(_cpu),
      instQueue(_cpu, this, params),
      ldstQueue(_cpu, this, params),
      fuPool(params->fuPool),
      commitToExecuteDelay(params->commitToExecuteDelay),
      mapToExecuteDelay(params->mapToExecuteDelay),
      issueToExecuteDelay(params->issueToExecuteDelay),
      dispatchWidth(params->dispatchWidth),
      issueWidth(params->issueWidth),
      wbOutstanding(0),
      wbWidth(params->wbWidth),
      numThreads(params->numThreads),
      switchedOut(false)
{
    _status = Active;
    exeStatus = Running;
    wbStatus = Idle;

    // Setup wire to read instructions coming from issue.
    fromIssue = issueToExecQueue.getWire(-issueToExecuteDelay);

    // Instruction queue needs the queue between issue and execute.
    instQueue.setIssueToExecuteQueue(&issueToExecQueue);

    for (ThreadID tid = 0; tid < numThreads; tid++) {
        dispatchStatus[tid] = Running;
        stalls[tid].commit = false;
        fetchRedirect[tid] = false;
    }

    wbMax = wbWidth * params->wbDepth;

    updateLSQNextCycle = false;

    ableToIssue = true;

    skidBufferMax = (3 * (mapToExecuteDelay * params->mapWidth)) + issueWidth;

}

template <class Impl>
std::string
SimpleEdgeExecute<Impl>::name() const
{
    return cpu->name() + ".execute";
}

template <class Impl>
void
SimpleEdgeExecute<Impl>::regStats()
{
    using namespace Stats;

    instQueue.regStats();
    ldstQueue.regStats();

    executeIdleCycles
        .name(name() + ".executeIdleCycles")
        .desc("Number of cycles execute is idle");

    executeSquashCycles
        .name(name() + ".executeSquashCycles")
        .desc("Number of cycles execute is squashing");

    executeBlockCycles
        .name(name() + ".executeBlockCycles")
        .desc("Number of cycles execute is blocking");

    executeUnblockCycles
        .name(name() + ".executeUnblockCycles")
        .desc("Number of cycles execute is unblocking");

    executeDispatchedInsts
        .name(name() + ".executeDispatchedInsts")
        .desc("Number of instructions dispatched to IQ");

    executeDispNopInsts
        .name(name() + ".executeDispatchedNopInsts")
        .desc("Number of NOPs dispatched to IQ");

    executeDispUsefulInsts
        .name(name() + ".executeDispatchedUsefulInsts")
        .desc("Number of instructions without NOP dispatched to IQ");
    executeDispUsefulInsts = executeDispatchedInsts - executeDispNopInsts;

    executeDispatchedInstBlocks
        .name(name() + ".executeDispatchedInstBlocks")
        .desc("Number of inst blocks dispatched to IQ");

    executeDispSquashedInsts
        .name(name() + ".executeDispSquashedInsts")
        .desc("Number of squashed insts skipped by dispatch");

    executeDispSquashedInstBlocks
        .name(name() + ".executeDispSquashedInstBlocks")
        .desc("Number of squashed inst blocks skipped by dispatch");

    executeDispLoadInsts
        .name(name() + ".executeDispLoadInsts")
        .desc("Number of dispatched load instructions");

    executeDispStoreInsts
        .name(name() + ".executeDispStoreInsts")
        .desc("Number of dispatched store instructions");

    executeDispNonSpecInstBlocks
        .name(name() + ".executeDispNonSpecInstBlocks")
        .desc("Number of dispatched non-speculative inst blocks");

    executeDispSpecInstBlocks
        .name(name() + ".executeDispSpecInstBlocks")
        .desc("Number of dispatched speculative inst blocks");
    executeDispSpecInstBlocks = executeDispatchedInstBlocks
                                                                                             - executeDispNonSpecInstBlocks;

    executeDispNonSpecInsts
        .name(name() + ".executeDispNonSpecInsts")
        .desc("Number of dispatched non-speculative instructions");

    executeDispSpecInsts
        .name(name() + ".executeDispSpecInsts")
        .desc("Number of dispatched speculative instructions");
    executeDispSpecInsts = executeDispatchedInsts - executeDispNonSpecInsts;

    executeIQFullEvents
        .name(name() + ".executeIQFullEvents")
        .desc("Number of times the IQ has become full, causing a stall");

    executeLSQFullEvents
        .name(name() + ".executeLSQFullEvents")
        .desc("Number of times the LSQ has become full, causing a stall");

    executeInFlightFullEvents
        .name(name() + ".executeInflightFullEvents")
        .desc("Number of times the max number of in-flight inst blocks reached, causing a stall");

    memOrderViolationEvents
        .name(name() + ".memOrderViolationEvents")
        .desc("Number of memory order violations");

    memLoadBlockedEvents
        .name(name() + ".memLoadBlockedEvents")
        .desc("Number of load blocked times");

    branchMispredicts
        .name(name() + ".branchMispredicts")
        .desc("Number of inst block mispredicts detected at execute");

    executeExecutedInsts
        .name(name() + ".executeExecutedInsts")
        .desc("Number of executed instructions");

    executeExecutedInstBlocks
        .name(name() + ".executeExecutedInstBlocks")
        .desc("Number of executed inst blocks");

    executeExecutedRefs
        .name(name() + ".EXEC:refs")
        .desc("number of memory reference insts executed");

    executeExecLoadInsts
        .name(name() + ".executeExecLoadInsts")
        .desc("Number of load instructions executed");

    executeExecStoreInsts
        .name(name() + ".EXEC:stores")
        .desc("Number of stores executed");
    executeExecStoreInsts = executeExecutedRefs - executeExecLoadInsts;

    executeExecSquashedInsts
        .name(name() + ".executeExecSquashedInsts")
        .desc("Number of squashed instructions skipped in execute");

    executeExecSquashedInstBlocks
        .name(name() + ".executeExecSquashedInstBlocks")
        .desc("Number of squashed inst blocks skipped in execute");

    executeExecRegReads
        .name(name() + ".EXEC:reg-reads")
        .desc("Number of register read executed");

     executeExecRegWrites
        .name(name() + ".EXEC:reg-writes")
        .desc("Number of register write executed");

     executeExecRegAcc
        .name(name() + ".EXEC:reg-Acc")
        .desc("Number of register accesses executed");
    executeExecRegAcc = executeExecRegReads + executeExecRegWrites;

    executeExecAvailCycles
        .name(name() + ".EXEC:availableCycles")
        .desc("Number of available cycles");

    executeExecRate
        .name(name() + ".EXEC:rate")
        .desc("Inst execution rate");
    executeExecRate = executeExecutedInsts / executeExecAvailCycles;

    executeExecNullifiedInsts
        .name(name() + ".EXEC:nullifiedInsts")
        .desc("Number of nullified insts");
    executeExecNullifiedInsts = executeExecNullifiedNormals +
                                executeExecNullifiedBranches +
                                executeExecNullifiedLoads +
                                executeExecNullifiedStores +
                                executeExecNullifiedWrites;

    executeExecNullifiedStores
        .name(name() + ".EXEC:nullified-stores")
        .desc("Number of nullified stores");

    executeExecNullifiedLoads
        .name(name() + ".EXEC:nullified-loads")
        .desc("Number of nullified loads");

    executeExecNullifiedWrites
        .name(name() + ".EXEC:nullified-writes")
        .desc("Number of nullified writes");

    executeExecNullifiedBranches
        .name(name() + ".EXEC:nullified-branches")
        .desc("Number of nullified branches");

     executeExecNullifiedNormals
        .name(name() + ".EXEC:nullified-normals")
        .desc("Number of nullified normals");

    executeInstBlocksToCommit
        .name(name() + ".instBlocksToCommit")
        .desc("Number of inst blocks sent to commit");

    executeInflightInstBlocks
        .init(0,Impl::MaxInFlightBlockNum,1)
        .name(name() + ".EXEC:In-flightInstBlocks")
        .desc("Number of inst blocks in flight each cycle")
        .flags(Stats::pdf)
        ;
        
    executeInflightInsts
        .init(0,Impl::MaxInFlightBlockNum * 160,50)
        .name(name() + ".EXEC:In-flightInsts")
        .desc("Number of insts in flight each cycle")
        .flags(Stats::pdf)
        ;        
}

template<class Impl>
void
SimpleEdgeExecute<Impl>::initStage()
{
    for (ThreadID tid = 0; tid < numThreads; tid++) {
        toMap->executeInfo[tid].usedIQ = true;
        toMap->executeInfo[tid].freeIQEntries =
            instQueue.numFreeEntries(tid);

        toMap->executeInfo[tid].usedLSQ = true;
        toMap->executeInfo[tid].freeLSQEntries =
            ldstQueue.numFreeEntries(tid);
    }

    cpu->activateStage(CPU::ExecuteIdx);

    // Init frame id to 0
    currFrameID = 0;
}

template<class Impl>
void
SimpleEdgeExecute<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
{
    timeBuffer = tb_ptr;

    // Setup wire to read information from time buffer, from commit.
    fromCommit = timeBuffer->getWire(-commitToExecuteDelay);

    // Setup wire to write information back to previous stages.
    toMap = timeBuffer->getWire(0);

    toFetch = timeBuffer->getWire(0);

    // Instruction queue also needs main time buffer.
    instQueue.setTimeBuffer(tb_ptr);
}

template<class Impl>
void
SimpleEdgeExecute<Impl>::setMapQueue(TimeBuffer<Map2Execute> *rq_ptr)
{
    map2executeQueue = rq_ptr;

    // Setup wire to read information from rename queue.
    fromMap = map2executeQueue->getWire(-mapToExecuteDelay);
}

template<class Impl>
void
SimpleEdgeExecute<Impl>::setExecuteQueue(TimeBuffer<Execute2Commit> *iq_ptr)
{
    execute2commitQueue = iq_ptr;

    // Setup wire to write instructions to commit.
    toCommit = execute2commitQueue->getWire(0);
}

template<class Impl>
void
SimpleEdgeExecute<Impl>::setActiveThreads(list<ThreadID> *at_ptr)
{
    activeThreads = at_ptr;

    ldstQueue.setActiveThreads(at_ptr);
    instQueue.setActiveThreads(at_ptr);
}

template <class Impl>
bool
SimpleEdgeExecute<Impl>::drain()
{
    // IEW is ready to drain at any time.
    cpu->signalDrained();
    return true;
}

template <class Impl>
void
SimpleEdgeExecute<Impl>::resume()
{
}

template <class Impl>
void
SimpleEdgeExecute<Impl>::switchOut()
{
    // Clear any state.
    switchedOut = true;
    assert(instBlocks[0].empty());
    assert(skidBuffer[0].empty());

    instQueue.switchOut();
    ldstQueue.switchOut();
    fuPool->switchOut();

    for (ThreadID tid = 0; tid < numThreads; tid++) {
        while (!instBlocks[tid].empty())
            instBlocks[tid].pop();
        while (!skidBuffer[tid].empty())
            skidBuffer[tid].pop();
    }
}

template <class Impl>
void
SimpleEdgeExecute<Impl>::takeOverFrom()
{
    // Reset all state.
    _status = Active;
    exeStatus = Running;
    wbStatus = Idle;
    switchedOut = false;

    instQueue.takeOverFrom();
    ldstQueue.takeOverFrom();
    fuPool->takeOverFrom();

    initStage();
    cpu->activityThisCycle();

    for (ThreadID tid = 0; tid < numThreads; tid++) {
        dispatchStatus[tid] = Running;
        stalls[tid].commit = false;
        fetchRedirect[tid] = false;
    }

    updateLSQNextCycle = false;

    for (int i = 0; i < issueToExecQueue.getSize(); ++i) {
        issueToExecQueue.advance();
    }
}

template<class Impl>
void
SimpleEdgeExecute<Impl>::squash(ThreadID tid)
{
    DPRINTF(EdgeExe, "[tid:%i]: Squashing all Blocks.\n", tid);

    ExeBlockIt block_it = instBlocksInExecuting.begin();
    ExeBlockIt end = instBlocksInExecuting.end();

    while (block_it != end) {
        if (block_it->first > fromCommit->commitInfo[tid].doneBlockID) {
            DPRINTF(EdgeExe, "[tid:%i]: Removing inst blocks[Bid:%lli]"
                    " in executing data structure.\n",
                    tid, block_it->first);

            executeExecSquashedInsts += (block_it->second->getNumUsefulInst());

            // See Nicolai M Josuttis_The C++ Standard Library
            instBlocksInExecuting.erase(block_it++);
            // Decrease the frame id to ensure the consistency in IQ frames.
//            decCurrFrameID();

            executeExecSquashedInstBlocks++;
        } else {
            ++block_it;
        }
    }

    // Tell the IQ to start squashing.
    instQueue.squash(tid);

    // Tell the LDSTQ to start squashing.
    ldstQueue.squash(fromCommit->commitInfo[tid].doneBlockID, tid);

    updatedQueues = true;

    // Clear the skid buffer in case it has any data in it.
    DPRINTF(EdgeExe, "[tid:%i]: Removing skidbuffer Blocks until [id:%i].\n",
            tid, fromCommit->commitInfo[tid].doneBlockID);

    while (!skidBuffer[tid].empty()) {

        toMap->executeInfo[tid].dispatched++;

        skidBuffer[tid].pop();
    }

    emptyMapInstBlocks(tid);
}

template<class Impl>
void
SimpleEdgeExecute<Impl>::squashDueToSyscall(EdgeBlockPtr &inst_block, ThreadID tid)
{
    DPRINTF(EdgeExe, "[tid:%i]: Squashing due to syscall, PC: %#x "
            "[id:%i].\n", tid, inst_block->getStartPC(), inst_block->getBlockID());

    assert(inst_block->isNeedSyscall());

    toCommit->squash[tid] = true;
    toCommit->squashedSeqNum[tid] = inst_block->getBlockID();
    toCommit->nextPC[tid] = inst_block->getBranchTarget();

    toCommit->branchMispredict[tid] = false;
    toCommit->exitMispredict[tid] = false;

    toCommit->includeSquashInstBlock[tid] = false;

    wroteToTimeBuffer = true;
}

template<class Impl>
void
SimpleEdgeExecute<Impl>::squashDueToBranch(EdgeBlockPtr &inst_block, ThreadID tid)
{
    DPRINTF(EdgeExe, "[tid:%i]: Squashing from a specific block, PC: %#x "
            "[id:%i].\n", tid, inst_block->getStartPC(), inst_block->getBlockID());

    toCommit->squash[tid] = true;
    toCommit->squashedSeqNum[tid] = inst_block->getBlockID();
    toCommit->mispredPC[tid] = inst_block->getStartPC();
    toCommit->branchMispredict[tid] = true;
    toCommit->exitMispredict[tid] = inst_block->exitMispredicted();
    toCommit->seqMispredict[tid] = inst_block->seqMispredicted();
    toCommit->exitID = inst_block->getExitID();
    toCommit->predExitID = inst_block->getPredExitID();
    toCommit->exitType = inst_block->getExitType();

    toCommit->exitID = inst_block->getExitID();
    toCommit->exitType = inst_block->getExitType();

    toCommit->branchTaken[tid] =
        inst_block->getNextBlockPC() != inst_block->getBranchTarget();

    toCommit->nextPC[tid] = inst_block->getBranchTarget();

    toCommit->includeSquashInstBlock[tid] = false;

    wroteToTimeBuffer = true;
}

template<class Impl>
void
SimpleEdgeExecute<Impl>::squashDueToMemOrder(EdgeBlockPtr &inst_block, ThreadID tid)
{
    DPRINTF(EdgeExe, "[tid:%i]: Squashing from a specific block, "
            "PC: %#x [id:%i].\n", tid, inst_block->getStartPC(), inst_block->getBlockID());

    toCommit->squash[tid] = true;
    toCommit->squashedSeqNum[tid] = inst_block->getBlockID();
    toCommit->nextPC[tid] = inst_block->getNextBlockPC();

    toCommit->branchMispredict[tid] = false;

    toCommit->includeSquashInstBlock[tid] = false;

    wroteToTimeBuffer = true;
}

template<class Impl>
void
SimpleEdgeExecute<Impl>::squashDueToMemBlocked(EdgeBlockPtr &inst_block, ThreadID tid)
{
    DPRINTF(EdgeExe, "[tid:%i]: Memory blocked, squashing this inst block, "
            "PC: %#x [id:%i].\n", tid, inst_block->getStartPC(), inst_block->getBlockID());

    toCommit->squash[tid] = true;
    toCommit->squashedSeqNum[tid] = inst_block->getBlockID();
    toCommit->nextPC[tid] = inst_block->getStartPC();

    toCommit->branchMispredict[tid] = false;

    // Must include the broadcasted SN in the squash.
    toCommit->includeSquashInstBlock[tid] = true;

    ldstQueue.setLoadBlockedHandled(tid);

    wroteToTimeBuffer = true;

    // Set the inst block as squashed
    inst_block->setSquashed();

}

template<class Impl>
void
SimpleEdgeExecute<Impl>::block(ThreadID tid)
{
    DPRINTF(EdgeExe, "[tid:%u]: Blocking.\n", tid);

    if (dispatchStatus[tid] != Blocked &&
        dispatchStatus[tid] != Unblocking) {
        toMap->executeBlock[tid] = true;
        wroteToTimeBuffer = true;
    }

    // Add the current inputs to the skid buffer so they can be
    // reprocessed when this stage unblocks.
    skidInsert(tid);

    dispatchStatus[tid] = Blocked;
}

template<class Impl>
void
SimpleEdgeExecute<Impl>::unblock(ThreadID tid)
{
    DPRINTF(EdgeExe, "[tid:%i]: Reading instructions out of the skid "
            "buffer %u.\n",tid, tid);

    // If the skid bufffer is empty, signal back to previous stages to unblock.
    // Also switch status to running.
    if (skidBuffer[tid].empty()) {
        toMap->executeUnblock[tid] = true;
        wroteToTimeBuffer = true;
        DPRINTF(EdgeExe, "[tid:%i]: Done unblocking.\n",tid);
        dispatchStatus[tid] = Running;
    }
}

//
// @todo: Operand network should be placed here.
//
template<class Impl>
void
SimpleEdgeExecute<Impl>::wakeDependents(DynInstPtr &inst)
{
    instQueue.wakeDependents(inst);
}

template<class Impl>
void
SimpleEdgeExecute<Impl>::completeMemInst(DynInstPtr &inst)
{
    instQueue.completeMemInst(inst);
}

template<class Impl>
void
SimpleEdgeExecute<Impl>::rescheduleMemInst(DynInstPtr &inst)
{
    instQueue.rescheduleMemInst(inst);
}

template<class Impl>
void
SimpleEdgeExecute<Impl>::replayMemInst(ThreadID tid)
{
    instQueue.replayMemInst(tid);
}

template<class Impl>
int
SimpleEdgeExecute<Impl>::getCurrFrameID()
{
    if ((++currFrameID) >= Impl::MaxFrameNum) {
        currFrameID = 0;
    }

    return currFrameID;
}

template<class Impl>
void
SimpleEdgeExecute<Impl>::decCurrFrameID()
{
    if ((--currFrameID) < 0){
        currFrameID = Impl::MaxFrameNum - 1;
    }
}

template<class Impl>
void
SimpleEdgeExecute<Impl>::instBlockToCommit(EdgeBlockPtr &inst_block)
{
    // Right now, most of the codes is inherited from O3 model.
    // It works right however, we should re-consider all of this
    // codes when I am free.
    while ((*execute2commitQueue)[wbCycle].instBlocks[wbNumInstBlock]) {
        ++wbNumInstBlock;
        if (wbNumInstBlock == wbWidth) {
            ++wbCycle;
            wbNumInstBlock = 0;
        }

        assert((wbCycle * wbWidth + wbNumInstBlock) <= wbMax);
    }

    DPRINTF(EdgeExe, "Current wb cycle: %i, width: %i,"
            " numInstBlock: %i\nwbActual:%i\n",
            wbCycle, wbWidth, wbNumInstBlock,
            wbCycle * wbWidth + wbNumInstBlock);

    // Add finished inst block to queue to commit.
    (*execute2commitQueue)[wbCycle].instBlocks[wbNumInstBlock] = inst_block;
    (*execute2commitQueue)[wbCycle].size++;

    assert((*execute2commitQueue)[wbCycle].size <= Impl::MaxCompleteWidth);

    executeInstBlocksToCommit ++;

}

template <class Impl>
unsigned
SimpleEdgeExecute<Impl>::validInstBlocksFromMap()
{
    unsigned inst_count = 0;

    for (int i=0; i<fromMap->size; i++) {
        if (!fromMap->instBlocks[i]->isSquashed())
            inst_count++;
    }

    return inst_count;
}

template<class Impl>
void
SimpleEdgeExecute<Impl>::skidInsert(ThreadID tid)
{
    EdgeBlockPtr inst_block = NULL;

    while (!instBlocks[tid].empty()) {
        inst_block = instBlocks[tid].front();

        instBlocks[tid].pop();

        DPRINTF(EdgeExe,"[tid:%i]: Inserting [id:%lli] PC:%#x into "
                "dispatch skidBuffer %i\n",
                tid,
                inst_block->getBlockID(),
                inst_block->getStartPC(),tid);

        skidBuffer[tid].push(inst_block);
    }

    assert(skidBuffer[tid].size() <= skidBufferMax &&
           "Skidbuffer Exceeded Max Size");
}

template<class Impl>
int
SimpleEdgeExecute<Impl>::skidCount()
{
    int max=0;

    list<ThreadID>::iterator threads = activeThreads->begin();
    list<ThreadID>::iterator end = activeThreads->end();

    while (threads != end) {
        ThreadID tid = *threads++;
        unsigned thread_count = skidBuffer[tid].size();
        if (max < thread_count)
            max = thread_count;
    }

    return max;
}

template<class Impl>
bool
SimpleEdgeExecute<Impl>::skidsEmpty()
{
    list<ThreadID>::iterator threads = activeThreads->begin();
    list<ThreadID>::iterator end = activeThreads->end();

    while (threads != end) {
        ThreadID tid = *threads++;

        if (!skidBuffer[tid].empty())
            return false;
    }

    return true;
}

template <class Impl>
void
SimpleEdgeExecute<Impl>::updateStatus()
{
    bool any_unblocking = false;

    list<ThreadID>::iterator threads = activeThreads->begin();
    list<ThreadID>::iterator end = activeThreads->end();

    while (threads != end) {
        ThreadID tid = *threads++;

        if (dispatchStatus[tid] == Unblocking) {
            any_unblocking = true;
            break;
        }
    }

    // If there are no ready instructions waiting to be scheduled by the IQ,
    // and there's no stores waiting to write back, and dispatch is not
    // unblocking, then there is no internal activity for the Execute stage.
    if (_status == Active && !instQueue.hasReadyInsts() &&
        !ldstQueue.willWB() && !any_unblocking) {
        DPRINTF(EdgeExe, "Execute switching to idle\n");

        deactivateStage();

        _status = Inactive;
    } else if (_status == Inactive && (instQueue.hasReadyInsts() ||
                                       ldstQueue.willWB() ||
                                       any_unblocking)) {
        // Otherwise there is internal activity.  Set to active.
        DPRINTF(EdgeExe, "Execute switching to active\n");

        activateStage();

        _status = Active;
    }
}

template <class Impl>
void
SimpleEdgeExecute<Impl>::resetEntries()
{
    instQueue.resetEntries();
    ldstQueue.resetEntries();
}

template <class Impl>
void
SimpleEdgeExecute<Impl>::readStallSignals(ThreadID tid)
{
    if (fromCommit->commitBlock[tid]) {
        stalls[tid].commit = true;
    }

    if (fromCommit->commitUnblock[tid]) {
        assert(stalls[tid].commit);
        stalls[tid].commit = false;
    }
}

template <class Impl>
bool
SimpleEdgeExecute<Impl>::checkStall(ThreadID tid)
{
    bool ret_val(false);

    if (stalls[tid].commit) {
        DPRINTF(EdgeExe,"[tid:%i]: Stall from Commit stage detected.\n",tid);
        ret_val = true;
    } else if (instQueue.isFull(tid)) {
        DPRINTF(EdgeExe,"[tid:%i]: Stall: IQ  is full.\n",tid);
        ret_val = true;
    } else if (ldstQueue.isFull(tid)) {
        DPRINTF(EdgeExe,"[tid:%i]: Stall: LSQ is full\n",tid);

        if (ldstQueue.numLoads(tid) > 0 ) {

            DPRINTF(EdgeExe,"[tid:%i]: LSQ oldest load: [sn:%i] \n",
                    tid,ldstQueue.getLoadHeadSeqNum(tid));
        }

        if (ldstQueue.numStores(tid) > 0) {

            DPRINTF(EdgeExe,"[tid:%i]: LSQ oldest store: [sn:%i] \n",
                    tid,ldstQueue.getStoreHeadSeqNum(tid));
        }

        ret_val = true;
    } else if (ldstQueue.isStalled(tid)) {
        DPRINTF(EdgeExe,"[tid:%i]: Stall: LSQ stall detected.\n",tid);
        ret_val = true;
    }

    return ret_val;
}

template <class Impl>
void
SimpleEdgeExecute<Impl>::checkSignalsAndUpdate(ThreadID tid)
{
    // Check if there's a squash signal, squash if there is
    // Check stall signals, block if there is.
    // If status was Blocked
    //     if so then go to unblocking
    // If status was Squashing
    //     check if squashing is not high.  Switch to running this cycle.

    readStallSignals(tid);

    if (fromCommit->commitInfo[tid].squash) {
        squash(tid);

        if (dispatchStatus[tid] == Blocked ||
            dispatchStatus[tid] == Unblocking) {
            toMap->executeUnblock[tid] = true;
            wroteToTimeBuffer = true;
        }

        dispatchStatus[tid] = Squashing;

        fetchRedirect[tid] = false;
        return;
    }

    if (fromCommit->commitInfo[tid].robSquashing) {
        DPRINTF(EdgeExe, "[tid:%i]: ROB is still squashing.\n", tid);

        dispatchStatus[tid] = Squashing;

        emptyMapInstBlocks(tid);
        wroteToTimeBuffer = true;
        return;
    }

    if (checkStall(tid)) {
        block(tid);
        dispatchStatus[tid] = Blocked;
        return;
    }

    if (dispatchStatus[tid] == Blocked) {
        // Status from previous cycle was blocked, but there are no more stall
        // conditions.  Switch over to unblocking.
        DPRINTF(EdgeExe, "[tid:%i]: Done blocking, switching to unblocking.\n",
                tid);

        dispatchStatus[tid] = Unblocking;

        unblock(tid);

        return;
    }

    if (dispatchStatus[tid] == Squashing) {
        // Switch status to running if rename isn't being told to block or
        // squash this cycle.
        DPRINTF(EdgeExe, "[tid:%i]: Done squashing, switching to running.\n",
                tid);

        dispatchStatus[tid] = Running;

        return;
    }
}

template <class Impl>
void
SimpleEdgeExecute<Impl>::sortInstBlocks()
{
    int blocks_from_map = fromMap->size;

#ifdef DEBUG
    for (ThreadID tid = 0; tid < numThreads; tid++)
        assert(instBlocks[tid].empty());
#endif

    for (int i = 0; i < blocks_from_map; ++i) {
        instBlocks[(fromMap->instBlocks[i])->getTid()].push(fromMap->instBlocks[i]);
    }

}

template <class Impl>
void
SimpleEdgeExecute<Impl>::emptyMapInstBlocks(ThreadID tid)
{
    DPRINTF(EdgeExe, "[tid:%i]: Removing incoming map blocks\n", tid);

    while (!instBlocks[tid].empty()) {
        instBlocks[tid].pop();
    }
}

template <class Impl>
void
SimpleEdgeExecute<Impl>::wakeCPU()
{
    cpu->wakeCPU();
}

template <class Impl>
void
SimpleEdgeExecute<Impl>::activityThisCycle()
{
    DPRINTF(Activity, "Activity this cycle.\n");
    cpu->activityThisCycle();
}

template <class Impl>
inline void
SimpleEdgeExecute<Impl>::activateStage()
{
    DPRINTF(Activity, "Activating stage.\n");
    cpu->activateStage(CPU::ExecuteIdx);
}

template <class Impl>
inline void
SimpleEdgeExecute<Impl>::deactivateStage()
{
    DPRINTF(Activity, "Deactivating stage.\n");
    cpu->deactivateStage(CPU::ExecuteIdx);
}

template<class Impl>
void
SimpleEdgeExecute<Impl>::dispatch(ThreadID tid)
{
    // If status is Running or idle,
    //     call dispatchInsts()
    // If status is Unblocking,
    //     buffer any instructions coming from rename
    //     continue trying to empty skid buffer
    //     check if stall conditions have passed

    if (dispatchStatus[tid] == Blocked) {
        ++executeBlockCycles;

    } else if (dispatchStatus[tid] == Squashing) {
        ++executeSquashCycles;
    }

    // Dispatch should try to dispatch as many instructions as its bandwidth
    // will allow, as long as it is not currently blocked.
    if (dispatchStatus[tid] == Running ||
        dispatchStatus[tid] == Idle) {
        DPRINTF(EdgeExe, "[tid:%i] Not blocked, so attempting to run "
                "dispatch.\n", tid);

        dispatchInsts(tid);
    } else if (dispatchStatus[tid] == Unblocking) {
        // Make sure that the skid buffer has something in it if the
        // status is unblocking.
        assert(!skidsEmpty());

        // If the status was unblocking, then instructions from the skid
        // buffer were used.  Remove those instructions and handle
        // the rest of unblocking.
        dispatchInsts(tid);

        ++executeUnblockCycles;

        if (validInstBlocksFromMap()) {
            // Add the current inputs to the skid buffer so they can be
            // reprocessed when this stage unblocks.
            skidInsert(tid);
        }

        unblock(tid);
    }
}

template <class Impl>
void
SimpleEdgeExecute<Impl>::dispatchInsts(ThreadID tid)
{
    // Obtain instructions from skid buffer if unblocking, or queue from map
    // otherwise.
    std::queue<EdgeBlockPtr> &inst_blocks_to_dispatch =
        dispatchStatus[tid] == Unblocking ?
        skidBuffer[tid] : instBlocks[tid];

    int inst_blocks_to_add = inst_blocks_to_dispatch.size();

    EdgeBlockPtr inst_block;
    int dis_num_inst_block = 0;

    // Loop through the instructions, putting them in the instruction
    // queue.
    for ( ; dis_num_inst_block < inst_blocks_to_add &&
              dis_num_inst_block < dispatchWidth;
          ++dis_num_inst_block) {

        inst_block = inst_blocks_to_dispatch.front();

        if (dispatchStatus[tid] == Unblocking) {
            DPRINTF(EdgeExe, "[tid:%i]: Issue: Examining instruction from skid "
                    "buffer\n", tid);
        }

        // Make sure there's a valid instruction block there.
        assert(inst_block);

        DPRINTF(EdgeExe, "[tid:%i]: Issue: Adding PC %#x [id:%lli][tid:%i]"
                " to IQ.\n",
                tid, inst_block->getStartPC(),
                inst_block->getBlockID(),
                inst_block->getTid());

        // Be sure to mark these instructions as ready so that the
        // commit stage can go ahead and execute them, and mark
        // them as issued so the IQ doesn't reprocess them.

        // Check for squashed instructions.
        if (inst_block->isSquashed()) {
            DPRINTF(EdgeExe, "[tid:%i]: Issue: Squashed instruction encountered, "
                    "not adding to IQ.\n", tid);

            ++executeDispSquashedInstBlocks;

            executeDispSquashedInsts += inst_block->getNumUsefulInst();

            inst_blocks_to_dispatch.pop();

            toMap->executeInfo[tid].dispatched++;

            continue;
        }

        // Check for full conditions.
        if (instQueue.numFreeEntries(tid) < inst_block->getBlockSize()) {

            DPRINTF(EdgeExe, "[tid:%i]: Issue: Not enough IQ entries"
                    " for inst block. "
                    "IQ has %i freeentries, while %i insts to dispatch.\n",
                    tid,instQueue.numFreeEntries(tid),
                    inst_block->getBlockSize());

            // Call function to start blocking.
            block(tid);

            // Set unblock to false. Special case where we are using
            // skidbuffer (unblocking) instructions but then we still
            // get full in the IQ.
            toMap->executeUnblock[tid] = false;

            ++executeIQFullEvents;

            break;

        } else if (ldstQueue.numFreeEntries(tid) < inst_block->getNumMemRefInst()) {

            DPRINTF(EdgeExe, "[tid:%i]: Issue: Not enough LSQ"
                    " entries for inst block\n",tid);

            // Call function to start blocking.
            block(tid);

            // Set unblock to false. Special case where we are using
            // skidbuffer (unblocking) instructions but then we still
            // get full in the IQ.
            toMap->executeUnblock[tid] = false;

            ++executeLSQFullEvents;

            break;

        } else if (instBlocksInExecuting.size() >= Impl::MaxInFlightBlockNum) {

            DPRINTF(EdgeExe, "[tid:%i]: Issue: Max num of inflight blocks"
                    " is reached. \n",tid);

            block(tid);

            toMap->executeUnblock[tid] = false;

            ++executeInFlightFullEvents;

            break;

        }

        // Allocate a frame to this inst block.
//        inst_block->setFrameID(this->getCurrFrameID());

        DPRINTF(EdgeExe,"Issue to frame [id:%i].\n", inst_block->getFrameID());

        // Dispatching register reads.
        std::bitset<TheISA::HeaderSize>& read_mask = inst_block->getReadMask();
        int dis_read_idx = 0;
        int dis_read_num = 0;
        int num_reads = inst_block->getNumRegReadInst();

        while (dis_read_num < num_reads) {

            if (read_mask[dis_read_idx]) {
                DynInstPtr inst = inst_block->getRead(dis_read_idx);

                assert(inst->isRead());

                instQueue.insert(inst, dis_read_idx);

                executeDispatchedInsts++;
                toMap->executeInfo[tid].dispatched++;

                dis_read_num++;
            }

            assert(dis_read_idx < TheISA::HeaderSize);

            dis_read_idx++;
        }

        // Dispatching register writes.
        std::bitset<TheISA::HeaderSize>& write_mask = inst_block->getWriteMask();
        int dis_write_idx = 0;
        int dis_write_num = 0;
        int num_writes = inst_block->getNumRegWriteInst();

        while (dis_write_num < num_writes) {

            if (write_mask[dis_write_idx]) {
                DynInstPtr inst = inst_block->getWrite(dis_write_idx);

                assert(inst->isWrite());

                instQueue.insert(inst, dis_write_idx);

                executeDispatchedInsts++;
                toMap->executeInfo[tid].dispatched++;

                dis_write_num++;
            }

            assert(dis_write_idx < TheISA::HeaderSize);

            dis_write_idx++;
        }

        // Dispatching normal instructions.
        int dis_inst_idx = 0;
        int inst_block_size = inst_block->getBlockSize();

        // Put instructions of the dispatching inst block into
        // IQ and LSQ respectively.
        while (dis_inst_idx < inst_block_size) {

            DynInstPtr inst = inst_block->getInst(dis_inst_idx);

            if (!inst) {
                // A NULL pointer means NOP inst.

                executeDispNopInsts++;
            } else {

                // All inst should be inserted into inst queue.
                instQueue.insert(inst, dis_inst_idx);
            }

            toMap->executeInfo[tid].dispatched++;
            dis_inst_idx++;

            executeDispatchedInsts++;

        }

        // Dispatching memory references and build the memory
        // reference dependents.
        int dis_num_mem_ref = 0;
        int num_mem_ref_in_block = inst_block->getNumMemRefInst();
        // Memory references will be got in LSID order (from 0 to ...)
        int lsid = 0;

        DPRINTF(EdgeExe, "Building memory dependencts for %i"
                " mem refs.\n", num_mem_ref_in_block);

        while (dis_num_mem_ref < num_mem_ref_in_block) {

            if (!inst_block->isLdstEntryValid(lsid)) {
                ++lsid;
                continue;
            }

            DPRINTF(EdgeExe, "Building memory dependents for LSID %i.\n",
                    lsid);

            std::vector<int> & mem_ref_idxs = 
                inst_block->getMemoryReferenceIdx(lsid);

            for (int idx = 0; idx < mem_ref_idxs.size(); idx++) {

                DynInstPtr inst = inst_block->getInst(mem_ref_idxs[idx]);

                assert(inst->isMemRef());
                instQueue.buildMemDependent(inst);

                if (inst->isLoad()) {

                    ldstQueue.insertLoad(inst);
                    executeDispLoadInsts++;

                } else if (inst->isStore()) {

                    ldstQueue.insertStore(inst);
                    executeDispStoreInsts++;

                }
            }

            dis_num_mem_ref += mem_ref_idxs.size();

            // We can never get a dynamical number of dispatched
            // memory references which is larger than the number of
            // memory references in the block.
            assert(dis_num_mem_ref <= num_mem_ref_in_block);

            lsid++;
        }

        // All the memory references should be dispatched.
        assert(inst_block->getNumMemRefInst() == dis_num_mem_ref);

        //Add dispatched inst block into executing list
        inst_block->setExecuting();

        instBlocksInExecuting.insert(std::make_pair(inst_block->getBlockID(), 
                    inst_block));

        inst_blocks_to_dispatch.pop();

        ++executeDispatchedInstBlocks;

        if (inst_block->isNonSpeculative()) {
            executeDispNonSpecInstBlocks++;
            executeDispNonSpecInsts += inst_block_size;
        }
    }

    if (!inst_blocks_to_dispatch.empty() && dispatchStatus[tid] != Blocked) {

        DPRINTF(EdgeExe,"[tid:%i]: Issue: Bandwidth Full. Blocking.\n", tid);

        block(tid);
        toMap->executeUnblock[tid] = false;

    }

    if (dispatchStatus[tid] == Idle && dis_num_inst_block) {
        dispatchStatus[tid] = Running;

        updatedQueues = true;
    }
}

template <class Impl>
void
SimpleEdgeExecute<Impl>::executeInstBlocks()
{
    wbNumInstBlock = 0;
    wbCycle = 0;

    list<ThreadID>::iterator threads = activeThreads->begin();
    list<ThreadID>::iterator end = activeThreads->end();

    while (threads != end) {
        ThreadID tid = *threads++;
        fetchRedirect[tid] = false;
    }

    // Execute any instructions that are available.
    int insts_to_execute = fromIssue->size;

    if (insts_to_execute > 0) {
        ++executeExecAvailCycles;
    }

    int inst_num = 0;
    bool need_replay = false;

    for (; inst_num < insts_to_execute;
          ++inst_num) {

        DPRINTF(EdgeExe, "Execute: Executing instructions from IQ.\n");

        // Get instructions from IQ to execute.
        DynInstPtr inst = instQueue.getInstToExecute();

        // Can never execute nop inst.
        assert(!inst->isNop());

        DPRINTF(EdgeExe, "Execute: Processing PC %#x, [Tid:%i][Bid:%i] [Iid:%i].\n",
                inst->readPC(), inst->threadNumber,
                inst->getBlockID(), inst->getInstID());

        // Insts are from inst blocks, so maybe they can never
        // be set as squashed..
        // But I still reserve this codes for consistency with
        // M5 and future use.
        if (inst->isSquashed()) {
            DPRINTF(EdgeExe, "Execute: Instruction was squashed.\n");

            executeExecSquashedInsts ++;

            continue;
        }

        if (inst->isBlockCompleted()) {
            DPRINTF(EdgeExe,"Execute: Instruction was block completed.\n");

            continue;
        }

        Fault fault = NoFault;
        bool can_wakeup = true;

        // Execute instructions.
        // Note that if the instruction faults, it will be handled
        // at the commit stage.

        // Note that the data token type will be set during wakeup
        // if the inst is the propagator rather than the token
        // generator

        // @todo: Arithmatic, reg-op and control insts could generate
        // fault, need handling.

        if (inst->isMemRef()) {
            DPRINTF(EdgeExe, "Execute: Mem-ref instructions, calculating"
                    " address for memory reference.\n");

            // Tell the LDSTQ to execute this instruction (if it is a load).
            if (inst->isLoad()) {

                // If load inst has been nullified, ignore it.
                if (!inst->isNullified()) {

                    // For load insts, wake dependents of consumers will be handled
                    // in the write-back event of load inst.
                    // If load has been nullified, wakeup its
                    // consumer and propagate the token as well.
                    can_wakeup = false;

                    fault = ldstQueue.executeLoad(inst);
                } else {
                    // @todo: Maybe we should propagate the null token rather than
                    // ignore it.
                    DPRINTF(EdgeExe, "Nullified load, ignore it\n");

                    executeExecNullifiedLoads ++;

                    inst->setIntResult(0);
                    //inst->setExecuted();
                }

                // Do not mark load inst as executed here.
                // It will be marked as executed once upon
                // its writeback event happens.
                //inst->setExecuted();

                // If load caused a fault, we should set its output token
                // to exception and set a fake result to wake up dependence.
                if (fault != NoFault) {
                    DPRINTF(EdgeExe, "Load has fault!\n");

                    // A execption token generated.
                    inst->setDataflowTokenType ( TheISA::Exception );
                    inst->setIntResult(0);

                    // If the load got fault it will never write-back,
                    // so wake its consumers to propagate the fault.
                    can_wakeup = true;
                }

                executeExecLoadInsts ++;

            } else if (inst->isStore()) {

                // Get current block of this store inst in executing
                ExeBlockIt block_it = instBlocksInExecuting.find(inst->getBlockID());

                if (!inst->isNullified()) {
                    fault = ldstQueue.executeStore(inst);
                } else {
                    DPRINTF(EdgeExe, "Nullified store, ignore it\n");

                    // If store is nullified, some operations should be taken in
                    // LSQ so as to avoid write-back while committing.
                    ldstQueue.nullifyStore(inst);

                    (block_it->second)->nullifyStore(inst->staticInst->getLSID());

                    executeExecNullifiedStores++;
                }

                // Mark store inst as executed.
                inst->setExecuted();

                // Increment executed number of stores in this block
                (block_it->second)->incReceivedStore(inst->staticInst->getLSID(),
                                                     inst->getInstID());


                DPRINTF(EdgeExe, "Set store mask with lsid %i\n",
                        inst->staticInst->getLSID() );

                if (fault != NoFault) {
                    // If the instruction faulted, then we need to set the fault
                    // to its block class so that commit can handle it.

                    // There's no need for changing the store data token type
                    // to execption because it's the leaf of whole graph.
                    DPRINTF(EdgeExe, "Store has fault %s! [Bid:%lli][Iid:%lli]\n",
                            fault->name(), inst->getBlockID(), inst->getInstID() );

                    (block_it->second)->setFault(fault);

                    inst->setExecuted();

                    activityThisCycle();
                } else {

                    // Store recevie fault from other insts.

                    fault = inst->getFault();

                    if (fault != NoFault) {

                        (block_it->second)->setFault(fault );

                        DPRINTF(EdgeExe, "Store receive fault %s [Bid%lli][Iid%lli]"
                                ", set it to block.\n",
                                fault->name(), 
                                inst->getBlockID(), 
                                inst->getInstID() );
                    }
                }
            } else {
                panic("Unexpected memory type!\n");
            }

            executeExecutedRefs ++;

        } else if (inst->isGRegWR()) {

            if (inst->isRead()) {
                // Reg read will never be nullified, no need to handle it.

                DPRINTF(EdgeExe, "Executing reg-read.\n" );

                //inst->setExecutingReadReg();
                inst->execute();

                // Mark reg read as executed.
                inst->setExecuted();

                executeExecRegReads++;

            } else if (inst->isWrite()) {
                // Write reg will always be leaf in graph and
                // it will be executed during write back phase,
                // so if it has been nullified, we will handle
                // it in write-back phase.
                // Write back will be casted after commit stages comfirmed it.
                DPRINTF(EdgeExe, "Executing reg-write.\n");

                // Mark the inst as executed for forwarding.
                inst->setExecuted();
                //inst->setCanCommit();

                // Complete it in reg dep graph.
                instQueue.completeInRegDepGraph(inst);

                // Get current block in executing
                ExeBlockIt block_it = instBlocksInExecuting.find(inst->getBlockID());

                // Increment executed number of writes in this block
                (block_it->second)->incReceivedWrite();

                fault = inst->getFault();

                if (fault != NoFault) {

                    (block_it->second)->setFault(fault);

                    DPRINTF(EdgeExe, "Reg-write has fault %s [Bid%lli][Iid%lli]"
                            ", set it to block.\n",
                            fault->name(), 
                            inst->getBlockID(), 
                            inst->getInstID() );
                }

                // Reg-write has no consumer, no need to wakeup.
                can_wakeup = false;

                executeExecRegWrites++;

                if (inst->isNullified()) executeExecNullifiedWrites++;

            } else {
                panic("Don't know how to execute register inst.\n");
            }

        } else if (inst->isControl()) {

            ExeBlockIt block_it = instBlocksInExecuting.find(inst->getBlockID());

            if (!inst->isNullified()) {
                // Execute pc control inst
                inst->execute();

                // branch target has been set in execute of this control inst
                (block_it->second)->incReceivedExit();
                (block_it->second)->recordExitID(inst->staticInst->getEXIT());
                (block_it->second)->recordExitType(inst->staticInst->isCall(),
                                                   inst->staticInst->isReturn(),
                                                   inst->staticInst->isIndirectCtrl());

                if (inst->isSyscall()) {
                    DPRINTF(EdgeExe, "Syscall inst, mark block as need syscall.\n");

                    (block_it->second)->setNeedSyscall();
                }
            } else {
                // Nullified control inst, ignore it.
                 DPRINTF(EdgeExe, "Control inst has been nullified\n");
                 executeExecNullifiedBranches ++;
            }

            inst->setExecuted();

            fault = inst->getFault();
            if (fault != NoFault) {

                // Control inst receive fault from others, mark it in block
                (block_it->second)->setFault(fault);

                DPRINTF(EdgeExe, "Control has fault %s [Bid%lli][Iid%lli]"
                        ", set it to block.\n",
                        fault->name(), 
                        inst->getBlockID(), 
                        inst->getInstID() );
            }
        } else {

            if (!inst->isNullified()) {

                inst->execute();

            } else {

                // For consistency
                inst->setIntResult(0);
                DPRINTF(EdgeExe, "Normal inst nullified\n");

                executeExecNullifiedNormals ++;

            }

            inst->setExecuted();
        }

        // Wakeup consumers and propagate token with respect to
        // different situations.
        if (can_wakeup) {
            instQueue.wakeDependents(inst);
        }

        ThreadID tid = inst->threadNumber;

        if (ldstQueue.violation(tid)) {

            assert(inst->isMemRef());
            // If there was an ordering violation, then get the
            // DynInst that caused the violation.  Note that this
            // clears the violation signal.
            DynInstPtr violator;
            violator = ldstQueue.getMemDepViolator(tid);

            DPRINTF(EdgeExe, "LDSTQ detected a violation.  Violator PC: "
                    "%#x, inst PC: %#x.  Addr is: %#x.\n",
                    violator->readPC(),
                    inst->readPC(),
                    inst->physEffAddr);

            // Tell the instruction queue that a violation has occured.
            instQueue.violation(inst, violator);

            // Record faults in corresponding inst blocks.
            ExeBlockIt block_it = instBlocksInExecuting.find(inst->getBlockID());
            (block_it->second)->setFault();

            // Squash.
            squashDueToMemOrder(block_it->second,tid);

            ++memOrderViolationEvents;

        } else if (ldstQueue.loadBlocked(tid) &&
                   !ldstQueue.isLoadBlockedHandled(tid)) {

            // Only load will cause the ldstQueue to be LOADBLOCKED!
            assert(inst->isLoad());

            DPRINTF(EdgeExe, "Load operation couldn't execute because the "
                    "memory system is blocked."
                    " PC: %#x [Bid:%lli][Iid:%lli].\n",
                    inst->readPC(),
                    inst->getBlockID(),
                    inst->getInstID());

            rescheduleMemInst(inst);

            if (!need_replay) {
                need_replay = true;
            }

            // Each time we replay this load, flags indicating that
            // the ldst queue is LOADBLOCKED will be reset.
            ldstQueue.clearLoadBlocked(tid);
            ldstQueue.setLoadBlockedHandled(tid);

            ++memLoadBlockedEvents;
        }
        executeExecutedInsts++;
    }

    // Replay if needed.
    if (need_replay) {
        threads = activeThreads->begin();

        while (threads != end) {
            ThreadID tid = *threads++;
            replayMemInst(tid);
        }
    }

    // Update and record activity if we processed any instructions.
    if (inst_num) {

        if (exeStatus == Idle) {
            exeStatus = Running;
        }

        updatedQueues = true;

        cpu->activityThisCycle();
    }

    // Need to reset this in case a writeback event needs to write into the
    // iew queue.  That way the writeback event will write into the correct
    // spot in the queue.
    wbNumInstBlock = 0;
}

template<class Impl>
void
SimpleEdgeExecute<Impl>::completeInstBlocks()
{
    // Check for completed blocks.
    ExeBlockIt block_it = instBlocksInExecuting.begin();
    ExeBlockIt end = instBlocksInExecuting.end();

    while (block_it != end) {
        // Once the block completed, mark it and move it to commit.
        // Remember the reg write insts and mem store insts in this
        // block will be still existed in LSQ and IQ unless there's a
        // commit signal coming from commit stage. Remove the inst
        // block from in-executing structure when it really commits.
        EdgeBlockPtr inst_block = block_it->second;

        bool completed_cond_satisfied = 
            inst_block->isCompletionCondSatisfied();

        // The inst block has been marked as completed, pass it.
        if (inst_block->isCompleted()) {

            DPRINTF(EdgeExe, "Block[Bid:%lli]] @%#x has already completed.\n",
                    inst_block->getBlockID(),
                    inst_block->getStartPC());

            ++block_it;

            continue;
        }

        if (inst_block->isSquashed()) {

            DPRINTF(EdgeExe, "Block[Bid:%lli] @%#x is squashed.\n",
            inst_block->getBlockID(),
            inst_block->getStartPC());

            inst_block->setCompleted();

            instBlockToCommit(inst_block);

        } else if (inst_block->isNop()) {

                DPRINTF(EdgeExe, "Block[Bid:%lli] @%#x is a nop inst block,"
                        " sent it to commit directly.\n",
                inst_block->getBlockID(),
                inst_block->getStartPC());

            inst_block->setCompleted();

            instBlockToCommit(inst_block);

        } else if (completed_cond_satisfied &&
                   inst_block->isNonSpeculative()) {

            DPRINTF(EdgeExe, "Block[Bid:%lli] @%#x completed,"
                    " send it to commit.\n",
                    inst_block->getBlockID(),
                    inst_block->getStartPC() );

            inst_block->setCompleted();

            instQueue.complete(inst_block);

            if (inst_block->isNeedSyscall()) {

                DPRINTF(EdgeExe, "Syscall is required by this block.\n");

                inst_block->setSyscallBranchTarget();

                //squashDueToSyscall(inst_block, inst_block->getTid());
            }

            if (inst_block->misPredicted()) {
                DPRINTF(EdgeExe, "Miss prediction detected!\n");
                DPRINTF(EdgeExe, "Block[id:%lli] @%#x: real target: %#x"
                        ", miss predicted target: %#x\n",
                        inst_block->getBlockID(),
                        inst_block->getStartPC(),
                        inst_block->getBranchTarget(),
                        inst_block->getPredBranchTarget());

                // If this block has a fault, it will squash in the
                // commit stage. So no need to handle it as a branch
                // misprediction.
                if (inst_block->getFault() == NoFault) {
                    squashDueToBranch(inst_block, inst_block->getTid());
                    branchMispredicts++;
                }
            }

            instBlockToCommit(inst_block);

            executeExecutedInstBlocks++;

        } else if (completed_cond_satisfied) {
            DPRINTF(EdgeExe, "Inst block[Bid:%lli] @%#x completed in"
                    " speculative status, waiting.\n",
                    inst_block->getBlockID(),
                    inst_block->getStartPC());

            executeExecutedInstBlocks++;
        }

        ++block_it;
    }
}

template<class Impl>
void
SimpleEdgeExecute<Impl>::tick()
{
    wbNumInstBlock = 0;
    wbCycle = 0;

    wroteToTimeBuffer = false;
    updatedQueues = false;

    sortInstBlocks();

    // Free function units marked as being freed this cycle.
    // Function units should be divided into ETs...
    fuPool->processFreeUnits();

    list<ThreadID>::iterator threads = activeThreads->begin();
    list<ThreadID>::iterator end = activeThreads->end();

    // Check stall and squash signals, dispatch any instructions.
    while (threads != end) {
        ThreadID tid = *threads++;

        DPRINTF(EdgeExe,"Issue: Processing [tid:%i]\n",tid);
        checkSignalsAndUpdate(tid);

        // Actually, I need to dispatch insts in one block.
        // But I still want some integrity as a block class
        // should hold all informations about inst blocks.

        dispatch(tid);
    }

    if (exeStatus != Squashing) {

        // Execute ready insts in IQ. Instructions
        // in IQ could be from different inst blocks.
        executeInstBlocks();

        // Check for inst block completion condition.
        completeInstBlocks();

        // Have the instruction queue try to schedule any ready instructions.
        // (In actuality, this scheduling is for instructions that will
        // be executed next cycle.)
        instQueue.scheduleReadyInsts();

        // Also should advance its own time buffers if the stage ran.
        // Not the best place for it, but this works (hopefully).
        issueToExecQueue.advance();
    }

    bool broadcast_free_entries = false;

    if (updatedQueues || exeStatus == Running || updateLSQNextCycle) {
        exeStatus = Idle;
        updateLSQNextCycle = false;

        broadcast_free_entries = true;
    }

    // Writeback any stores. 
    ldstQueue.writebackStores();

    threads = activeThreads->begin();
    while (threads != end) {

        ThreadID tid = (*threads++);
        BlockID commit_bid = fromCommit->commitInfo[tid].doneBlockID;

        DPRINTF(EdgeExe,"Try to writeback comitted inst blocks.[tid:%i]\n",tid);

        // Update structures based on instructions committed.
        // Write back inst blocks and retire it.
        if (commit_bid != 0 &&
            !fromCommit->commitInfo[tid].squash &&
            !fromCommit->commitInfo[tid].robSquashing) {

            // If block has fault, it will be informed by commit to squash.
            // We'll never reach this in that circumstance.

            ldstQueue.commitStores(commit_bid,tid);

            ldstQueue.commitLoads(commit_bid,tid);

            updateLSQNextCycle = true;

            // This will write back write-reg insts.
            instQueue.writeBack(commit_bid, tid);

            // This will retire instructions in IQ belong to the committed
            // inst block.
            instQueue.commit(commit_bid,tid);

            assert(!instBlocksInExecuting.empty());
            assert(instBlocksInExecuting.size() <= Impl::MaxInFlightBlockNum);

            int num = 0;

            DPRINTF(EdgeBlockCount, "Ref count of Block[Bid:%lli] is"
                    " %i. Num of stores is %i.\n", commit_bid,
                    instBlocksInExecuting[commit_bid]->getCount(),
                    instBlocksInExecuting[commit_bid]->getNumStoreInst());

            num = instBlocksInExecuting.erase(commit_bid);
            // We can just commit exactly 1 block.
            assert(num == 1);

            if (fromCommit->commitInfo[tid].needSyscall) {
                // This block need syscall, handle it.

                DPRINTF(EdgeExe, "Need syscall, handle it\n");

                // This fault will not redirect the PC, so no need to
                // inform the cpu that we invoke a syscall fault.
                // 
                // System call will write register and memory
                // externally, thus we should squash all the
                // instruction blocks younger than syscall block to
                // guarantee the coherency. In syscall fault invoke
                // method, the PC and some registers like r3, r4 will
                // be set externally, which will cause the pipeline
                // to squash. Consequently we can avoid calling the
                // squashDueToSyscall method explicitly to squash the
                // pipeline.
                Fault fault = TheISA::genSyscallFault();
                fault->invoke(cpu->thread[tid]->getTC());

                // Tell the fetch stage that a syscall is handled.
                toFetch->executeInfo[tid].syscall = true;
                toFetch->executeInfo[tid].syscallBlockID = commit_bid;
            }
        }

        if (broadcast_free_entries) {
            toFetch->executeInfo[tid].iqCount =
                instQueue.getCount(tid);
            toFetch->executeInfo[tid].ldstqCount =
                ldstQueue.getCount(tid);

            toMap->executeInfo[tid].usedIQ = true;
            toMap->executeInfo[tid].freeIQEntries =
                instQueue.numFreeEntries();
            toMap->executeInfo[tid].usedLSQ = true;
            toMap->executeInfo[tid].freeLSQEntries =
                ldstQueue.numFreeEntries(tid);

            wroteToTimeBuffer = true;
        }

        DPRINTF(EdgeExe, "[tid:%i], Dispatch dispatched %i instructions.\n",
                tid, toMap->executeInfo[tid].dispatched);
    }

    DPRINTF(EdgeExe, "IQ has %i free entries (Can schedule: %i).  "
            "LSQ has %i free entries.\n",
            instQueue.numFreeEntries(), instQueue.hasReadyInsts(),
            ldstQueue.numFreeEntries());

    updateStatus();

    if (wroteToTimeBuffer) {
        DPRINTF(Activity, "Activity this cycle.\n");
        cpu->activityThisCycle();
    }

    updateExeInstBlockStats();
}

template <class Impl>
void
SimpleEdgeExecute<Impl>::updateExeInstBlockStats()
{
    executeInflightInstBlocks.sample(instBlocksInExecuting.size());
    
    ExeBlockIt block_it = instBlocksInExecuting.begin();
    ExeBlockIt end = instBlocksInExecuting.end();

    int infligh_insts = 0;
    while (block_it != end) {
        infligh_insts += (block_it->second)->getNumUsefulInst();
        block_it++;
    }
    executeInflightInsts.sample(infligh_insts);
}
